/*
git config --global user.name "ASxx" 
git config --global user.email "123456789@qq.com"

git init
touch README.md
git add README.md
git commit -m "test"
git remote add origin https://git.oschina.net/name/package.git
git push -u origin master

git pull --rebase origin master
git config --global credential.helper
运行一下命令缓存输入的用户名和密码：
git config --global credential.helper wincred
清除掉缓存在git中的用户名和密码
git credential-manager uninstall
估计自己要登录一次
*/
#include <Adafruit_NeoPixel.h>
#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
#include "OneButton.h"
#include "protothreads.h"
#include <EEPROM.h>
#include <ESP8266WiFi.h>
#include <stdio.h>

#define NEOPIXEL_PIN 12
#define NEOPIXEL_LED_NUM 360
#define COLOR_NUM 7

#define UCS1903_PIN 15

#define LED_NUM 45

#define OLED_IIC_SCL 5
#define OLED_IIC_SDA 4

#define BT_MODE_PIN 0  //ok
#define BT_UP_PIN 2    //ok
#define BT_DOWN_PIN 14 //若15则接上拉电阻

#define BAUDRATE 115200

#define IR_HEAD_PIN 13 //15启动时不能高，只能低，可接幻彩
#define IR_TAIL_PIN 16

#define LONG_PRESS_CNT 360 //ms

#define EEPROM_ADDR 0

#define CHINESE 0

#define SSP 5 //led流水速度调节参数
#define LSP  (3 * SSP) //led流水速度调节参数

unsigned char option_num;
unsigned char clearDisplayCnt = 0;

enum options //代替#define
{
  STAIR_NUM,
  STAIR_SPEED,
  LED_LEN,
  LED_COLOR,
  LED_SPEED,
  WAIT_TIME,
  STAIR_MODE,
  RESET,
};

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NEOPIXEL_LED_NUM, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel f_led = Adafruit_NeoPixel(LED_NUM / 3, UCS1903_PIN, NEO_GRB + NEO_KHZ800);

U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE, /* clock=*/OLED_IIC_SCL, /* data=*/OLED_IIC_SDA);

OneButton button_up(BT_UP_PIN, true);
OneButton button_down(BT_DOWN_PIN, true);
OneButton button_mode(BT_MODE_PIN, true);
//OneButton button_flash(BT_FLASH_PIN, true);
void Click_cb_U(int btId);
void LongPress_cb_LED_LEN(int btId);

pt button_check;
pt led_head_stream;
pt led_tail_stream;
pt led_show;
pt stair_head_stream;
pt stair_tail_stream;
pt stair_show;
pt ir_check;

bool UCS1903_data[LED_NUM] = {1, 0, 0, 1};

unsigned char clickCnt = 0;
bool ir_head_flag = 0;
bool ir_tail_flag = 0;
unsigned char led_state = 0;
unsigned char stair_state = 0;

unsigned char stair_num = LED_NUM;
uint32_t LedColor[COLOR_NUM + 1];

struct Menu_option
{
  const char *name;
  byte id;
  byte val;    //unsigned char
  byte maxVal; //不要赋值
  byte minVal;
  void (*ClickCallback)(int btId);
  void (*DoubleClickCallback)(int btId);
  void (*LongPressCallback)(int btId);
};

struct Menu_option Menu_options[] =
    {
        {CHINESE ? ". 楼梯级数: " : ".Stair Num: ", STAIR_NUM, 20, 45, 0, Click_cb_U, NULL, Click_cb_U},
        {CHINESE ? ". 楼梯灯流速: " : ".stair speed: ", STAIR_SPEED, 2, 10, 0, Click_cb_U, NULL, Click_cb_U},
        {CHINESE ? ". 扶手灯数: " : ".led num: ", LED_LEN, 6, 204, 0, Click_cb_U, NULL, LongPress_cb_LED_LEN},
        {CHINESE ? ". 扶手灯颜色: " : ".Led Color: ", LED_COLOR, 2, COLOR_NUM, 0, Click_cb_U, NULL, Click_cb_U},
        {CHINESE ? ". 扶手灯流速: " : ".Led Speed: ", LED_SPEED, 2, 10, 0, Click_cb_U, NULL, Click_cb_U},
        {CHINESE ? ". 扶手灯延时: " : ".Wait Time: ", WAIT_TIME, 5, 20, 0, Click_cb_U, NULL, Click_cb_U},
        {CHINESE ? ". 楼梯灯模式: " : ".Stair Mode: ", STAIR_MODE, 1, 6, 0, Click_cb_U, NULL, Click_cb_U},
        {CHINESE ? ". 参数重置: " : ".Reset: ", RESET, 1, 2, 0, Click_cb_U, NULL, Click_cb_U}};

/*
初始化菜单项
1、计算菜单项目数
2、根据菜单id调节菜单在结构体数组的位置
3、如果菜单id有重复等错误终止程序
*/
void menu_init()
{
  struct Menu_option Menu_option_tmp;

  option_num = sizeof(Menu_options) / sizeof(struct Menu_option);
  for (int i = 0; i < option_num; i++)
  {
    if (Menu_options[i].id != i)
    {
      for (int j = i; j < option_num; j++)
      {
        if (Menu_options[j].id == i)
        {
          memcpy(&Menu_option_tmp, &Menu_options[i], sizeof(Menu_option_tmp));
          memcpy(&Menu_options[i], &Menu_options[j], sizeof(Menu_option_tmp));
          memcpy(&Menu_options[j], &Menu_option_tmp, sizeof(Menu_option_tmp));
          break;
        }
        if (j == option_num - 1)
        {
          return;
        }
      }
    }
  }
}

//关闭wifi，系统自动调用
void preinit()
{
  ESP8266WiFiClass::preinitWiFiOff();
}

/*
颜色压缩 
*/
uint32_t Wheel(byte WheelPos)
{
  WheelPos = 255 - WheelPos;
  if (WheelPos < 85)
  {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if (WheelPos < 170)
  {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

//初始化颜色列表
void LedColorInit()
{
  for (int i = 1; i < COLOR_NUM + 1; i++)
  {
    LedColor[i] = Wheel(255 / COLOR_NUM * (i - 1)); //除数为0有危险
  }
}

void UCS1903_begin()
{
  f_led.begin();
}

void UCS1903_setState(bool state)
{
  for (int i = 0; i < LED_NUM; i++)
  {
    UCS1903_data[i] = state;
  }
}

void UCS1903_fillDataMode_1(unsigned char pos, unsigned char mode)
{
  UCS1903_data[pos] = 1;
}

void UCS1903_fillDataMode_2(unsigned char pos, unsigned char mode)
{
  if (pos - 1 >= 0)
  {
    UCS1903_data[pos - 1] = 0;
  }
  if (pos + 1 < stair_num)
  {
    UCS1903_data[pos + 1] = 0;
  }
  UCS1903_data[pos] = 1;
}

void UCS1903_fillDataMode_3(unsigned char pos, unsigned char mode)
{
  if (pos - 1 >= 0)
    UCS1903_data[pos - 1] = 0;
  if (pos + 2 < stair_num)
    UCS1903_data[pos + 2] = 0;
  if (pos + 1 < stair_num)
  {
    UCS1903_data[pos + 1] = 1;
  }
  UCS1903_data[pos] = 1;
}

void UCS1903_fillDataMode_4(unsigned char pos, unsigned char mode)
{
  if (pos + 1 < stair_num)
    UCS1903_data[pos + 1] = 1;
  UCS1903_data[pos] = 1;
}

void UCS1903_fillDataMode_5(unsigned char pos, unsigned char mode)
{
  for (int i = 0; i < stair_num; i++)
  {
    if ((i + pos) % 3)
    {
      UCS1903_data[i] = 0;
    }
    else
    {
      UCS1903_data[i] = 1;
    }
  }
}
void UCS1903_fillDataMode_6(unsigned char pos, unsigned char mode)
{
  for (int i = 0; i < stair_num; i++)
  {
    UCS1903_data[i] = 1;
  }
}

void UCS1903_fillData(unsigned char pos, unsigned char mode, bool val)
{
  if (val == 0)
  {
    UCS1903_data[pos] = 0;
    return;
  }
  switch (mode)
  {
  case 1:
    UCS1903_fillDataMode_1(pos, mode);
    break;
  case 2:
    UCS1903_fillDataMode_2(pos, mode);
    break;
  case 3:
    UCS1903_fillDataMode_3(pos, mode);
    break;
  case 4:
    UCS1903_fillDataMode_4(pos, mode);
    break;
  case 5:
    UCS1903_fillDataMode_5(pos, mode);
    break;
  case 6:
    UCS1903_fillDataMode_6(pos, mode);
    break;
  }
}

void UCS1903_sendData()
{
  for (int i = 0; i < LED_NUM; i += 3)
  {
    f_led.setPixelColor(i / 3, 25 * UCS1903_data[i + 0], 25 * UCS1903_data[i + 1], 25 * UCS1903_data[i + 2]);
  }

  f_led.show();
}

void setUpdate(unsigned char c)
{
  switch (c)
  {
  case LED_LEN: //扶手灯数
    strip.clear();
    strip.show();
    strip.updateLength(Menu_options[LED_LEN].val * 10);
    break;
  case RESET: //重置
    EEPROM.write(EEPROM_ADDR + option_num, 0x0);
    EEPROM.commit();
    ESP.restart();
    break;
  case STAIR_NUM: //楼梯级数
    UCS1903_setState(0);
    UCS1903_sendData();
    stair_num = Menu_options[clickCnt].val;
  default:
    break;
  }
}

void LongPress_cb_LED_LEN(int btId)
{
  if (btId == 1) //减
  {
    Menu_options[clickCnt].val -= 10;
    if (Menu_options[clickCnt].val < Menu_options[clickCnt].minVal || Menu_options[clickCnt].val > Menu_options[clickCnt].maxVal)
    {
      Menu_options[clickCnt].val = Menu_options[clickCnt].maxVal;
    }
  }
  else if (btId == 2) //加
  {
    Menu_options[clickCnt].val += 10;
    if (Menu_options[clickCnt].val > Menu_options[clickCnt].maxVal)
    {
      Menu_options[clickCnt].val = Menu_options[clickCnt].minVal;
    }
  }
  EEPROM.write(EEPROM_ADDR + clickCnt, Menu_options[clickCnt].val);
  EEPROM.commit();
  u8g2.firstPage(); //显示
  do
  {
    u8g2.setCursor(0, 32);
    u8g2.print(Menu_options[clickCnt].name);
    u8g2.setCursor(42, 52);
    if (clickCnt != LED_LEN)
    {
      u8g2.print(Menu_options[clickCnt].val);
    }
    else
    {
      u8g2.print(Menu_options[clickCnt].val * 10);
    }
    //u8g2.print(Menu_options[clickCnt].val);
  } while (u8g2.nextPage());
  setUpdate(clickCnt);
}

void Click_cb_U(int btId)
{
  if (btId == 1) //减
  {
    Menu_options[clickCnt].val -= 1;
    if (Menu_options[clickCnt].val < Menu_options[clickCnt].minVal || Menu_options[clickCnt].val > Menu_options[clickCnt].maxVal)
    {
      Menu_options[clickCnt].val = Menu_options[clickCnt].maxVal;
    }
  }
  else if (btId == 2) //加
  {
    Menu_options[clickCnt].val += 1;
    if (Menu_options[clickCnt].val > Menu_options[clickCnt].maxVal)
    {
      Menu_options[clickCnt].val = Menu_options[clickCnt].minVal;
    }
  }
  EEPROM.write(EEPROM_ADDR + clickCnt, Menu_options[clickCnt].val);
  EEPROM.commit();
  u8g2.firstPage(); //显示
  do
  {
    u8g2.setCursor(0, 32);
    u8g2.print(Menu_options[clickCnt].name);
    u8g2.setCursor(42, 52);
    if (clickCnt != LED_LEN)
    {
      u8g2.print(Menu_options[clickCnt].val);
    }
    else//特例
    {
      u8g2.print(Menu_options[clickCnt].val * 10);
    }
    //u8g2.print(Menu_options[clickCnt].val);
  } while (u8g2.nextPage());
  setUpdate(clickCnt);
}

void bt_click_cb(void *btId)
{
  static unsigned long timePre;
  int *Id_tmp = (int *)btId;
  if (millis() - timePre > LONG_PRESS_CNT) //限定连续按的时长
  {
    clearDisplayCnt = 0;
    timePre = millis();
    Menu_options[clickCnt].ClickCallback(*Id_tmp);
  }
}
void btDown_click_cb()
{
  static unsigned long timePre;
  if (millis() - timePre > LONG_PRESS_CNT) //限定连续按的时长
  {
    clearDisplayCnt = 0;
    timePre = millis();
    Menu_options[clickCnt].ClickCallback(1);
  }
}

void btUp_click_cb()
{
  static unsigned long timePre;
  if (millis() - timePre > LONG_PRESS_CNT)
  {
    clearDisplayCnt = 0;
    timePre = millis();
    Menu_options[clickCnt].ClickCallback(2);
  }
}

void btDown_longPress_cb()
{
  static unsigned long timePre;
  if (millis() - timePre > LONG_PRESS_CNT + 300) //限定连续按的时长
  {
    clearDisplayCnt = 0;
    timePre = millis();
    Menu_options[clickCnt].LongPressCallback(1);
  }
}

void btUp_longPress_cb()
{
  static unsigned long timePre;
  if (millis() - timePre > LONG_PRESS_CNT)
  {
    clearDisplayCnt = 0;
    timePre = millis();
    Menu_options[clickCnt].LongPressCallback(2);
  }
}

void btMode_click_cb()
{
  static unsigned long timePre;
  if (millis() - timePre > LONG_PRESS_CNT)
  {
    clearDisplayCnt = 0;
    timePre = millis();
    clickCnt++;
    if (clickCnt >= option_num)
    {
      clickCnt = 0;
    }

    char pos = clickCnt < 4 ? clickCnt : 3;
    //char pos_tmp = clickCnt<4?0:clickCnt-3;
    char pos_tmp = clickCnt - pos;
    u8g2.firstPage();
    do
    {
      u8g2.setCursor(0, pos * 16 + 15);
      u8g2.print(">");            //显示光标
      for (int i = 0; i < 4; i++) //显示四行信息
      {
        u8g2.setCursor(13, 15 + i * 16);
        u8g2.print((i + 1 + pos_tmp) % (option_num + 1));
        u8g2.print(Menu_options[(i + pos_tmp) % option_num].name);
        if ((i + pos_tmp) % option_num != LED_LEN)
        {
          u8g2.print(Menu_options[(i + pos_tmp) % option_num].val);
        }
        else
        {
          u8g2.print(Menu_options[(i + pos_tmp) % option_num].val * 10);
        }
      }
    } while (u8g2.nextPage());
  }
}

void btMode_doubleClick_cb()
{
  static unsigned long timePre;
  if (millis() - timePre > LONG_PRESS_CNT)
  {
    clearDisplayCnt = 0;
    timePre = millis();
    clickCnt--;
    if (clickCnt < 0 || clickCnt >= option_num)
    {
      clickCnt = option_num-1;
    }

    char pos = clickCnt < 4 ? clickCnt : 3; //算出光标所在行数
    //char pos_tmp = clickCnt<4?0:clickCnt-3;
    char pos_tmp = clickCnt - pos;
    u8g2.firstPage();
    do
    {
      u8g2.setCursor(0, pos * 16 + 15);
      u8g2.print(">");            //显示光标
      for (int i = 0; i < 4; i++) //显示四行信息
      {
        u8g2.setCursor(13, 15 + i * 16);
        u8g2.print((i + 1 + pos_tmp) % (option_num + 1));
        u8g2.print(Menu_options[(i + pos_tmp) % option_num].name);
        if ((i + pos_tmp) % option_num != LED_LEN)
        {
          u8g2.print(Menu_options[(i + pos_tmp) % option_num].val);
        }
        else
        {
          u8g2.print(Menu_options[(i + pos_tmp) % option_num].val * 10);
        }
      }
    } while (u8g2.nextPage());
  }
}

int button_check_thread(struct pt *pt)
{
  PT_BEGIN(pt);
  for (;;)
  {
    button_up.tick();
    button_down.tick();
    button_mode.tick();
    PT_SLEEP(pt, 20);
  }
  PT_END(pt);
}

int ir_check_thread(struct pt *pt)
{
  PT_BEGIN(pt);
  for (;;)
  {
    //如果没有被触发和不在流程的第二阶段就读取检测结果
    if (ir_head_flag == 0 && led_state < 2)
    {
      ir_head_flag = digitalRead(IR_HEAD_PIN);
    }
    if (ir_tail_flag == 0 && led_state < 2)
    {
      ir_tail_flag = digitalRead(IR_TAIL_PIN);
    }
    if(clearDisplayCnt > 90)
    {
      clickCnt--;
      btMode_click_cb();
    }else{
      clearDisplayCnt++;
    }

    PT_SLEEP(pt, 100);
  }
  PT_END(pt);
}

uint16_t led_head_cnt;
uint16_t led_tail_cnt;
unsigned char stair_head_cnt = 0;
unsigned char stair_tail_cnt = 0;

//led流水分为3阶段，亮-等-灭
int led_control_head_thread(struct pt *pt)
{

  PT_BEGIN(pt);
  for (;;)
  {
    if (ir_head_flag == 1)
    {
      //阶段1
      led_state = 1;
      for (stair_head_cnt = led_head_cnt = 0; led_head_cnt < strip.numPixels(); led_head_cnt++)
      {
        strip.setPixelColor(led_head_cnt, LedColor[Menu_options[LED_COLOR].val]);
        //fill_led_color(1, LedColor[Menu_options[LED_COLOR].val]);
        PT_SLEEP(pt, SSP * (Menu_options[LED_SPEED].maxVal - Menu_options[LED_SPEED].val));
      }
      //阶段2，协商另一端
      if (ir_tail_flag == 1 && led_tail_cnt < strip.numPixels())
      {
        while (led_state != 3)
        {
          PT_SLEEP(pt, 10);
        }
      }
      else
      {
        led_state = 2;
        PT_SLEEP(pt, 1000 * Menu_options[WAIT_TIME].val);
      }
      //阶段3
      led_state = 3;
      for (stair_head_cnt = led_head_cnt = 0; led_head_cnt < strip.numPixels(); led_head_cnt++)
      {
        strip.setPixelColor(led_head_cnt, strip.Color(0,0,0));
        //fill_led_color(1, strip.Color(0, 0, 0));
        PT_SLEEP(pt, SSP * (Menu_options[LED_SPEED].maxVal - Menu_options[LED_SPEED].val));
      }
      led_state = 0;
      ir_head_flag = 0;
    }
    PT_SLEEP(pt, 20);
  }
  PT_END(pt);
}

int led_control_tail_thread(struct pt *pt)
{

  PT_BEGIN(pt);
  for (;;)
  {
    if (ir_tail_flag == 1)
    {
      led_state = 1;
      for (stair_tail_cnt = led_tail_cnt = 0; led_tail_cnt < strip.numPixels(); led_tail_cnt++)
      {
        //fill_led_color(0, LedColor[Menu_options[LED_COLOR].val]);
        strip.setPixelColor(strip.numPixels() -1 - led_tail_cnt, LedColor[Menu_options[LED_COLOR].val]);
        PT_SLEEP(pt, SSP * (Menu_options[LED_SPEED].maxVal - Menu_options[LED_SPEED].val));
      }

      if (ir_head_flag == 1 && led_head_cnt < strip.numPixels())
      {
        while (led_state != 3)
        {
          PT_SLEEP(pt, 10);
        }
      }
      else
      {
        led_state = 2;
        PT_SLEEP(pt, 1000 * Menu_options[WAIT_TIME].val);
      }

      led_state = 3;
      for (stair_tail_cnt = led_tail_cnt = 0; led_tail_cnt < strip.numPixels(); led_tail_cnt++)
      {
        strip.setPixelColor(strip.numPixels() -1 - led_tail_cnt, strip.Color(0,0,0));
        //fill_led_color(0, strip.Color(0, 0, 0));
        PT_SLEEP(pt, SSP * (Menu_options[LED_SPEED].maxVal - Menu_options[LED_SPEED].val));
      }
      led_state = 0;
      ir_tail_flag = 0;
    }
    PT_SLEEP(pt, 20);
  }
  PT_END(pt);
}

int led_show_thread(struct pt *pt)
{

  PT_BEGIN(pt);
  for (;;)
  {
    if (led_state == 1 || led_state == 3)
    {
      strip.show();
      //UCS1903_sendData();
      PT_SLEEP(pt, SSP * (Menu_options[LED_SPEED].maxVal - Menu_options[LED_SPEED].val));
    }
    else if (led_state == 2)
    {
      PT_SLEEP(pt, 100 * Menu_options[WAIT_TIME].val);
    }
    else
    {
      PT_SLEEP(pt, 20);
    }
  }
  PT_END(pt);
}

int stair_control_head_thread(struct pt *pt)
{

  PT_BEGIN(pt);
  for (;;)
  {
    if (ir_head_flag == 1)
    {
      //阶段1
      stair_state = 1;
      for (stair_head_cnt = 0; stair_head_cnt < stair_num; stair_head_cnt++)
      {
        UCS1903_fillData(stair_head_cnt, Menu_options[STAIR_MODE].val, 1 );
        PT_SLEEP(pt, LSP * (Menu_options[STAIR_SPEED].maxVal - Menu_options[STAIR_SPEED].val));
      }
      //阶段2，协商另一端
      if (ir_tail_flag == 1 && stair_tail_cnt < stair_num)
      {
        while (stair_state != 3)
        {
          PT_SLEEP(pt, 10);
        }
      }
      else
      {
        stair_state = 2;
        PT_SLEEP(pt, 1000 * Menu_options[WAIT_TIME].val);
      }
      //阶段3
      stair_state = 3;
      for (stair_head_cnt = 0; stair_head_cnt < stair_num; stair_head_cnt++)
      {
        UCS1903_fillData(stair_head_cnt, Menu_options[STAIR_MODE].val, 0 );
        PT_SLEEP(pt, LSP * (Menu_options[STAIR_SPEED].maxVal - Menu_options[STAIR_SPEED].val));
      }
      stair_state = 0;
      ir_head_flag = 0;
    }
    PT_SLEEP(pt, 20);
  }
  PT_END(pt);
}

int stair_control_tail_thread(struct pt *pt)
{

  PT_BEGIN(pt);
  for (;;)
  {
    if (ir_tail_flag == 1)
    {
      stair_state = 1;
      for (stair_tail_cnt = 0; stair_tail_cnt < stair_num; stair_tail_cnt++)
      {
        UCS1903_fillData(stair_num - 1 - stair_tail_cnt, Menu_options[STAIR_MODE].val, 1 );
        PT_SLEEP(pt, LSP * (Menu_options[STAIR_SPEED].maxVal - Menu_options[STAIR_SPEED].val));
      }

      if (ir_head_flag == 1 && stair_head_cnt < stair_num)
      {
        while (stair_state != 3)
        {
          PT_SLEEP(pt, 10);
        }
      }
      else
      {
        stair_state = 2;
        PT_SLEEP(pt, 1000 * Menu_options[WAIT_TIME].val);
      }

      stair_state = 3;
      for (stair_tail_cnt = 0; stair_tail_cnt < stair_num; stair_tail_cnt++)
      {
        UCS1903_fillData(stair_num - 1 - stair_tail_cnt, Menu_options[STAIR_MODE].val, 0);
        PT_SLEEP(pt, LSP * (Menu_options[STAIR_SPEED].maxVal - Menu_options[STAIR_SPEED].val));
      }
      stair_state = 0;
      ir_tail_flag = 0;
    }
    PT_SLEEP(pt, 20);
  }
  PT_END(pt);
}

int stair_show_thread(struct pt *pt)
{

  PT_BEGIN(pt);
  for (;;)
  {
    if (stair_state == 1 || stair_state == 3)
    {
      UCS1903_sendData();
      PT_SLEEP(pt, LSP * (Menu_options[STAIR_SPEED].maxVal - Menu_options[STAIR_SPEED].val));
    }
    else if (stair_state == 2)
    {
      PT_SLEEP(pt, 100 * Menu_options[WAIT_TIME].val);
    }
    else
    {
      PT_SLEEP(pt, 20);
    }
  }
  PT_END(pt);
}

void setup()
{
  menu_init();

  PT_INIT(&button_check);
  PT_INIT(&led_head_stream);
  PT_INIT(&led_tail_stream);
  PT_INIT(&led_show);
  PT_INIT(&stair_head_stream);
  PT_INIT(&stair_tail_stream);
  PT_INIT(&stair_show);
  PT_INIT(&ir_check); //红外检测任务

  byte value;
  EEPROM.begin(option_num + 1); //数据个数
  value = EEPROM.read(EEPROM_ADDR + option_num);
  //判读标志是否为第一次启动
  if (value != 86)
  {
    for (int i = 0; i < option_num; i++)
    {
      EEPROM.write(EEPROM_ADDR + i, Menu_options[i].val);
    }
    EEPROM.write(EEPROM_ADDR + option_num, 86);
    EEPROM.commit();
  }
  else
  {
    for (int i = 0; i < option_num; i++)
    {
      Menu_options[i].val = EEPROM.read(EEPROM_ADDR + i);
    }
  }

  pinMode(IR_HEAD_PIN, INPUT);
  pinMode(IR_TAIL_PIN, INPUT);

  UCS1903_begin();
  UCS1903_setState(0);
  UCS1903_sendData();

  LedColorInit();
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'

  strip.updateLength(Menu_options[LED_LEN].val * 10);
  stair_num = Menu_options[STAIR_NUM].val;

  u8g2.begin();
#if CHINESE
  u8g2.enableUTF8Print();
  u8g2.setFont(u8g2_font_wqy13_t_gb2312); // 设置字体
#else
  u8g2.setFont(u8g2_font_ncenB10_tr);
#endif

  for (int i = 0; i < 128; i += 8)
  {
    u8g2.firstPage();
    do
    {
      u8g2.setCursor(i, 32);
      u8g2.print(CHINESE ? F("欢迎使用") : F("Welcome"));
    } while (u8g2.nextPage());
    delay(128 - i / 2);
  }
  clickCnt--;
  btMode_click_cb(); //初始显示一下

  button_up.attachClick(btUp_click_cb);
  button_up.attachDuringLongPress(btUp_longPress_cb);

  button_down.attachClick(btDown_click_cb);
  button_down.attachDuringLongPress(btDown_longPress_cb);
  button_mode.attachClick(btMode_click_cb);
  button_mode.attachDoubleClick(btMode_doubleClick_cb);
  button_mode.attachDuringLongPress(btMode_click_cb);
}

void loop()
{
  PT_SCHEDULE(button_check_thread(&button_check));
  PT_SCHEDULE(led_control_head_thread(&led_head_stream));
  PT_SCHEDULE(led_control_tail_thread(&led_tail_stream));
  PT_SCHEDULE(led_show_thread(&led_show));
  PT_SCHEDULE(stair_control_head_thread(&stair_head_stream));
  PT_SCHEDULE(stair_control_tail_thread(&stair_tail_stream));
  PT_SCHEDULE(stair_show_thread(&stair_show));
  PT_SCHEDULE(ir_check_thread(&ir_check));
}